# -*- coding: utf-8 -*-
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.GL.ARB.shader_objects import *
from OpenGL.GL.ARB.fragment_shader import *
from OpenGL.GL.ARB.vertex_shader import *
import sys,os

class ShaderWrapper(object):
    """Wrapper-Klasse zum einfachen Benutzen von Shadern.
    Zum Verwenden eines Shaders erst mit Shader-Namen initialisieren und dann nacheinander
    init_vertex_shader(), init_fragment_shader(), link_shaders() und use_shader_program()
    oder einfach use_shader() aufrufen.
    Variable können dann mit diversen Methoden der Klasse uebergeben werden."""

    def __init__(self, fragProgName, vertProgName=None, path="shader/"):
        if vertProgName==None:
            vertProgName = fragProgName+".vert"
            fragProgName += ".frag" 
        self.path = path
        self.fragProg = open(self.path+fragProgName, "r").read()
        self.vertProg = open(self.path+vertProgName, "r").read()
        self.vsHandle = None
        self.fsHandle = None
        self.shaderHandle = None
    
    
    def __init_shader(self, type, program):
        sHandle = glCreateShaderObjectARB(type)
        glShaderSourceARB(sHandle, [program])
        glCompileShaderARB(sHandle)
        success = glGetObjectParameterivARB(sHandle, GL_OBJECT_COMPILE_STATUS_ARB)
        if not success: 
            print glGetInfoLogARB(program)
        return sHandle

    def __link_shaders(self, vsHandle, fsHandle):
        if vsHandle or fsHandle:
            shaderHandle = glCreateProgramObjectARB()
        if self.vsHandle:
            glAttachObjectARB(shaderHandle, vsHandle)
            glDeleteObjectARB(vsHandle)
        if fsHandle:
            glAttachObjectARB(shaderHandle, fsHandle)
            glDeleteObjectARB(fsHandle)
        glLinkProgramARB(shaderHandle)
        success = glGetObjectParameterivARB(shaderHandle, GL_OBJECT_LINK_STATUS_ARB)
        if not success:
            print glGetInfoLogARB(shaderHandle)
        return shaderHandle

    
    def init_vertex_shader(self):
        """Initialisiert den Vertex-Shader"""
        self.vsHandle = self.__init_shader(GL_VERTEX_SHADER_ARB, self.vertProg)

    def init_fragment_shader(self):
        """Initialisiert den Fragment-Shader"""
        self.fsHandle = self.__init_shader(GL_FRAGMENT_SHADER_ARB, self.fragProg)

    def link_shaders(self):
        """Linkt die zwei Shader miteinander"""
        self.shaderHandle = self.__link_shaders(self.vsHandle, self.fsHandle)
        return self.shaderHandle

    def use_shader_program(self):
        """Fuegt den Shader in das Programm ein"""
        if self.shaderHandle:
            glUseProgramObjectARB(self.shaderHandle)
        else:
            print "Fehler: Kein Shader vorhanden!"
            glUseProgramObjectARB(0)
            
    def kill_shader_program(self):
        glUseProgramObjectARB(0)

    def use_shader(self):
        """Fuehrt alle notwendigen Schritte zum Benutzen eines Shaders aus"""
        self.init_vertex_shader()
        self.init_fragment_shader()
        self.link_shaders()
        self.use_shader_program()
        
    def send_vec2(self, var_name, value):
        var_location = glGetUniformLocationARB(self.shaderHandle, var_name)
        glUniform2fARB(var_location, *value)

    def send_vec3(self, var_name, value):
        var_location = glGetUniformLocationARB(self.shaderHandle, var_name)
        glUniform3fARB(var_location, *value)

    def send_vec4(self, var_name, value):
        var_location = glGetUniformLocationARB(self.shaderHandle, var_name)
        glUniform4fARB(var_location, *value)
        
    def send_matrix4(self, var_name, matrix):
        """sendet 4x4-Matrix an den Shader"""
        var_location = glGetUniformLocation(self.shaderHandle,var_name,matrix)
        glUniformMatrix4fv(var_location,1,GL_TRUE,matrix.tolist())

    def send_float(self, var_name, value):
        """sendet Float-Variable an den Shader"""
        var = glGetUniformLocationARB(self.shaderHandle, var_name)
        glUniform1fARB(var, value)

if __name__=='__main__':
    sw = ShaderWrapper("simpleColor_shader")

    
        
